File: rtiostream_tcpip.c

    1   /*
    2    * Copyright 1994-2012 The MathWorks, Inc.
    3    *
    4    * File: rtiostream_tcpip.c     
    5    *
    6    * Abstract: This source file implements both client-side and server-side TCP/IP
    7    *  and UDP/IP communication. Typically, this driver is used to support host-target
    8    *  communication where the client-side device driver runs on the host and the
    9    *  server-side driver runs on the target. For this implementation, both
   10    *  client-side and server-side driver code has been combined into a single
   11    *  file.
   12    *
   13    *  If you are using this code as a starting point to implement a TCP/IP or 
   14    *  UDP/IP driver for a custom target it is only necessary to include code 
   15    *  for the server side of the connection.
   16    */
   17   
   18   #ifndef _WIN32
   19   /* Required BSD Unix extensions are not available by default on certain Unix
   20    * distributions */
   21   #define _BSD_SOURCE
   22   #endif
   23   
   24   #include <stdio.h>
   25   #include <stdlib.h>
   26   #include <ctype.h>
   27   #include <string.h>
   28   #include <limits.h>
   29   #include "rtiostream.h"
   30   #include "tmwtypes.h"
   31   
   32   #ifdef _WIN32
   33     /* WINDOWS */
   34   
   35   #if defined(_MSC_VER)
   36    /* temporarily disable warning triggered
   37     * by windows.h */
   38    #pragma warning(push)
   39    #pragma warning(disable: 4255)
   40   #endif
   41   
   42   #include <windows.h>
   43   
   44   #if defined(_MSC_VER)
   45    /* restore warning */
   46    #pragma warning(pop)
   47   #endif
   48   
   49   # ifdef __LCC__
   50   # ifndef __LCC64__
   51   #   include <winsock2.h>
   52   # endif
   53   #   include <errno.h>
   54   # endif
   55   
   56   #define RTIOSTREAM_ECONNRESET WSAECONNRESET
   57   
   58   #elif defined(VXWORKS)
   59    /*VxWorks headers*/
   60   # include <selectLib.h>
   61   # include <sockLib.h>
   62   # include <inetLib.h>
   63   # include <ioLib.h>
   64   # include <taskLib.h>
   65   # include <netinet/tcp.h> 
   66   
   67   #define RTIOSTREAM_ECONNRESET ECONNRESET
   68   
   69   #else
   70     /* UNIX */
   71   # include <signal.h>
   72   # include <sys/time.h>      /* Linux */
   73   # include <sys/types.h>     /* Linux */
   74   # include <sys/socket.h>
   75   # include <netinet/in.h>    /* Linux */
   76   # include <netinet/tcp.h>   /* Linux */
   77   # include <arpa/inet.h>     /* Linux */
   78   # include <netdb.h>
   79   # include <errno.h>
   80   # include <fcntl.h>  
   81   # include <unistd.h>
   82   
   83   #define RTIOSTREAM_ECONNRESET ECONNRESET
   84   #endif
   85   
   86   #ifdef USE_MEXPRINTF
   87   #include "mex.h"
   88   #define printf mexPrintf
   89   #define SERVER_PORT_PRINTF(FORMAT, ARG1) mexPrintf(FORMAT, ARG1)
   90   #else
   91   /* If stdout is redirected to file, it is essential that the port number is 
   92    * available immediately in the output file. With LCC, printf does not flush 
   93    * correctly to the redirected output file - use fprintf & fflush instead. */
   94   #define SERVER_PORT_PRINTF(FORMAT, ARG1) fprintf(stdout, FORMAT, ARG1); \
   95                                            fflush(stdout)
   96   #endif
   97   
   98   /***************** DEFINES ****************************************************/
   99   
  100   #define HOSTNAME_MAXLEN (64U)
  101   
  102   #define SERVER_PORT_NUM  (17725U)   /* sqrt(pi)*10000 */
  103   
  104   /* 
  105    * EXT_BLOCKING  
  106    *
  107    * Depending on the implementation of the main program (e.g., grt_main.c,
  108    * rt_main.c), the EXT_BLOCKING flag must be set to either 0 or 1.
  109    *
  110    * rt_main.c (tornado/vxworks): rt_main.c is a real-time, multi-tasking target.
  111    * The upload and packet servers are called via background (low priority) tasks.
  112    * In this case, it is o.k. for the transport function to block as the blocked
  113    * tasks will simply be pre-empted in order to enable the model to run.  It is
  114    * desirable to block instead of to poll to free up the cpu for any other
  115    * potential work. 
  116    */
  117   #ifdef VXWORKS
  118   # define EXT_BLOCKING (1)  
  119   #else
  120   # define EXT_BLOCKING (0)  
  121   #endif
  122   
  123   /* timeout of 0 means to return immediately */
  124   #define BLOCKING_RECV_TIMEOUT_NOWAIT (0)
  125   /* timeout of -1 means to wait indefinitely */
  126   #define BLOCKING_RECV_TIMEOUT_NEVER (-1)
  127   /* rogue value for blocking receive timeout */
  128   #define DEFAULT_BLOCKING_RECV_TIMEOUT (-2)
  129   /* timeout of -3 means to wait for 10 ms to avoid high CPU load */
  130   #define BLOCKING_RECV_TIMEOUT_10MS (-3)
  131   /* wake up from blocking every second */
  132   #define DEFAULT_BLOCKING_RECV_TIMEOUT_SECS_CLIENT (1) 
  133   /* only wake up from blocking when data arrives */
  134   #define DEFAULT_BLOCKING_RECV_TIMEOUT_SECS_SERVER (BLOCKING_RECV_TIMEOUT_NEVER)
  135   /* server wait time for client to close its socket */
  136   #define BLOCKING_RECV_TIMEOUT_SOCK_SHUTDOWN (15)
  137   
  138   /* default isVerbose value */
  139   #define DEFAULT_IS_VERBOSE 0
  140   
  141   /* default protocol value */
  142   #define DEFAULT_PROTOCOL TCP_PROTOCOL
  143   /* allowed -protocol strings */
  144   #define TCP_PROTOCOL_STRING "TCP"
  145   #define UDP_PROTOCOL_STRING "UDP"
  146   #define UDP_PACKET_LOSS_DETECTON_PROTOCOL_STRING "UDP_PACKET_LOSS_DETECTION"
  147   
  148   /* default UDP max packet size 
  149    *
  150    * The maximum size of UDP packets that are transmitted / received must be
  151    * consistent on the host and target otherwise receive errors will occur at 
  152    * the side with the smaller buffer size specified.
  153    *
  154    * Use the "-maxudppacketsize SIZE" argument to specify a different packet size.
  155    * This option is particularly useful when using a custom server implementation
  156    * that uses a different max packet size to the default. 
  157    *
  158    * The maximum UDP payload is 65507 bytes, which can be achieved for localhost
  159    * based communications on Linux and Windows, but Mac has a lower size of
  160    * 9216.
  161    */
  162   #define UDP_MAX_PACKET_SIZE 9216
  163   #define DEFAULT_MAX_UDP_PACKET_SIZE UDP_MAX_PACKET_SIZE
  164   /* increase the UDP socket receive size to decrease the 
  165    * possibility of buffer overflow */
  166   #define UDP_SOCKET_RECEIVE_SIZE_REQUEST (512 * 1024) 
  167   
  168   #define DEFAULT_IS_USING_SEQ_NUM 1
  169   
  170   #ifdef WIN32
  171     /* WINDOWS */
  172   # define close closesocket
  173   # define SOCK_ERR SOCKET_ERROR
  174   #else
  175     /* UNIX, VXWORKS */
  176   # define INVALID_SOCKET (-1)
  177   # define SOCK_ERR (-1)
  178   
  179     typedef int SOCKET;
  180   #endif
  181   
  182   /* MIN utility */
  183   #ifndef MIN
  184   #define MIN(a,b) ((a) < (b) ? (a) : (b))
  185   #endif
  186   
  187   /***************** TYPEDEFS **************************************************/
  188   
  189   #if (defined(_WIN32)) || (defined(VXWORKS))
  190      /* socklen_t may not be available */
  191      typedef int rtiostream_socklen_t;
  192   #else
  193      typedef socklen_t rtiostream_socklen_t;
  194   #endif
  195   
  196   /* Server specific data structure */
  197   typedef struct ServerData_tag {
  198       int       port;           /* port number associated with the server socket */
  199       SOCKET    listenSock;     /* listening socket to accept incoming connections */
  200       char      *serverInfoFile; /* the filename that is used to write the server 
  201                                    port number when dynamic port allocation is used */                      
  202   } ServerData;
  203   
  204   /* UDP send / receive buffer data structure */
  205   typedef struct UDPPacketBuffer_tag {
  206       char * buffer; /* pointer to the buffer */
  207       char * dataPtr; /* pointer to the current position in the buffer */
  208       int dataAvail; /* amount of data in the buffer */
  209   } UDPPacketBuffer;
  210   
  211   /* Type for the optional UDP sequence number */
  212   typedef uint32_T udpSeqNum_T;
  213   /* byte size of the UDP sequence number */
  214   #define UDP_SEQ_NUM_SIZE ((int) sizeof(udpSeqNum_T))
  215   
  216   /* UDP specific data structure */
  217   typedef struct UDPData_tag {
  218      int isUsingSeqNum; /* is this connection using sequence numbers */
  219      int maxPacketSize; /* max packet size (buffer size) */
  220      UDPPacketBuffer * recvBuffer; /* buffer for an incoming datagram */
  221      UDPPacketBuffer * sendBuffer; /* buffer for an outgoing datagram */
  222      udpSeqNum_T sendSeqNum; /* sequence number to add to outgoing datagrams */
  223      udpSeqNum_T expectedRecvSeqNum; /* expected sequence number in incoming 
  224                                      datagrams */
  225      int resetExpectedRecvSeqNum; /* flags whether to reset expectedRecvSeqNum
  226                                      to the sequence number of the next incoming
  227                                      datagram */
  228   } UDPData;
  229   
  230   /* enum of supported communications protocols */
  231   typedef enum {TCP_PROTOCOL, UDP_PROTOCOL} CommsProtocol;
  232   
  233   /* Data encapsulating a single client / server connection  */
  234   typedef struct ConnectionData_tag {
  235      int isInUse; /* is this ConnectionData instance currently in use? */
  236      int isServer; /* is this ConnectionData instance a Server (or client)? */
  237      int blockingRecvTimeout; /*    Timeout value in seconds. rtIOStreamRecv 
  238                                     blocks until at least some of the requested 
  239                                     data is available or the timeout expires.   
  240                                     If a timeout occurs the receiveSize will be 0. 
  241   
  242                                     A value of BLOCKING_RECV_TIMEOUT_NOWAIT (0)
  243                                     means to block for 0 seconds (polling mode). 
  244                                     rtIOStreamRecv processes 
  245                                     any pending data or, if no data is available, 
  246                                     returns immediately with a receiveSize of 0.
  247   
  248                                     A value of BLOCKING_RECV_TIMEOUT_NEVER (-1)
  249                                     means to block indefinitely (full blocking 
  250                                     mode). rtIOStreamRecv blocks
  251                                     until at least some of the requested data is 
  252                                     available.   receiveSize should always be 
  253                                     greater than 0. 
  254   
  255                                     A value of BLOCKING_RECV_TIMEOUT_10MS (-3)
  256                                     means to block for up to 10 ms to avoid high CPU 
  257                                     load.
  258                                */
  259      int isVerbose; /* flag indicating whether to display verbose output */
  260      CommsProtocol protocol; /* TCP or UDP protocol */
  261      SOCKET sock; /* socket to send/receive packets */
  262      ServerData * serverData; /* Server specific data - NULL for clients */
  263      UDPData * udpData; /* UDP specific data - NULL for TCP */
  264   } ConnectionData;
  265   
  266   /**************** LOCAL DATA *************************************************/
  267   
  268   /* All local data resides in the per client / 
  269    * server instance ConnectionData structures to make sure each connection is
  270    * completely independent.
  271    *
  272    * Each ConnectionData does not use much memory; any optionally required 
  273    * send / recv buffers are dynamically allocated and freed when the ConnectionData 
  274    * actually becomes in use.
  275    *
  276    * The static array will be deallocated when the shared library is unloaded. 
  277    *
  278    * Using an array rather than a linked list allows us to have fast direct lookup
  279    * of ConnectionData from connectionID during calls to rtIOStreamSend/Recv */
  280   #define MAX_NUM_CONNECTIONS (50)
  281   static ConnectionData connectionDataArray[MAX_NUM_CONNECTIONS];
  282   
  283   /************** LOCAL FUNCTION PROTOTYPES ************************************/
  284   
  285   static int initConnectionData(int connectionID, 
  286                             int isServer, 
  287                             CommsProtocol protocol, 
  288                             SOCKET sock, 
  289                             int blockingRecvTimeout,
  290                             int maxPacketSize, 
  291                             int serverPort, 
  292                             char * serverInfoFile, 
  293                             int isVerbose, 
  294                             int isUsingSeqNum); 
  295   
  296   static int getConnectionID(void);
  297   
  298   static ConnectionData * getConnectionData(int connectionID);
  299   
  300   static void freeConnectionData(ConnectionData * connection);
  301   
  302   static UDPPacketBuffer * createUDPPacketBuffer(int maxPacketSize);
  303   
  304   static void freeUDPPacketBuffer(UDPPacketBuffer ** udpPacketBuffer);
  305   
  306   static void resetUDPPacketBuffer(UDPPacketBuffer * udpPacketBuffer);
  307   
  308   static int processUDPRecvSeqNum(ConnectionData * connection);
  309   
  310   static int initialUDPServerRecvfrom(ConnectionData * connection,
  311                                       struct sockaddr * clientSA,
  312                                       rtiostream_socklen_t * clientSALen);
  313   
  314   static int waitForClientClose(ConnectionData * connection);
  315   
  316   static int socketDataSet(
  317       ConnectionData * connection, 
  318       const void *src,
  319       const size_t size,
  320       size_t *sizeSent);
  321   
  322   static int socketDataGet(
  323       ConnectionData * connection, 
  324       char          *dst,
  325       const size_t   size,
  326       size_t        *sizeRecvd);
  327   
  328   static int socketDataPending(
  329       const SOCKET sock,
  330       ConnectionData * connection,
  331       int    *outPending,
  332       int timeoutSecs);
  333   
  334   static int serverStreamRecv( 
  335       ConnectionData * connection, 
  336       void * dst,
  337       size_t size,
  338       size_t * sizeRecvd);
  339   
  340   static SOCKET serverOpenSocket(int port, char * serverInfoFile, CommsProtocol protocol);
  341   
  342   #if (!defined(VXWORKS))
  343   static SOCKET clientOpenSocket(char * hostName, unsigned int portNum, CommsProtocol protocol);
  344   #endif
  345   
  346   static void serverAcceptSocket(ConnectionData * connection);
  347   
  348   static int processArgs(
  349       const int       argc,
  350       void         *  argv[],
  351       char        **  hostName, 
  352       unsigned int *  portNum,
  353       unsigned int *  isClient,
  354       int          *  isBlocking,
  355       int          *  recvTimeout, 
  356       char        **  serverInfoFile, 
  357       CommsProtocol * protocol, 
  358       int           * maxPacketSize,
  359       int           * isVerbose, 
  360       int           * isUsingSeqNum);
  361   
  362   #if (!defined(VXWORKS))
  363   static unsigned long nameLookup(char * hostName);
  364   #endif
  365   
  366   /*************** LOCAL FUNCTIONS **********************************************/
  367   
  368   /* Function: initConnectionData =================================================
  369    * Abstract:
  370    *  Initializes a client / server ConnectionData for the specified protocol.
  371    *
  372    *  A return value of RTIOSTREAM_ERROR indicates an error.
  373    */
  374   static int initConnectionData(int connectionID, 
  375                             int isServer, 
  376                             CommsProtocol protocol, 
  377                             SOCKET sock, 
  378                             int blockingRecvTimeout,
  379                             int maxPacketSize, 
  380                             int serverPort, 
  381                             char * serverInfoFile, 
  382                             int isVerbose, 
  383                             int isUsingSeqNum) {
  384      int retVal = RTIOSTREAM_NO_ERROR;
  385      ConnectionData * connection = &connectionDataArray[connectionID];
  386     
  387      /* initialize the new ConnectionData */
  388      connection->isInUse = 1;
  389      connection->isServer = isServer;
  390      connection->blockingRecvTimeout = blockingRecvTimeout;
  391      connection->protocol = protocol;
  392      connection->isVerbose = isVerbose;
  393      /* initialize to NULL early so that calls to 
  394       * freeConnectionData on error will succeed */
  395      connection->udpData = NULL;
  396      connection->serverData = NULL;
  397   
  398      if (protocol == UDP_PROTOCOL) {      
  399         /* initialize the UDP data */
  400         connection->udpData = malloc(sizeof(UDPData));
  401         if (connection->udpData == NULL) {
  402            printf("initConnectionData:UDPData malloc failed.\n");
  403            freeConnectionData(connection);
  404            retVal = RTIOSTREAM_ERROR;
  405            return retVal; 
  406         }
  407         /* initialize to NULL */
  408         connection->udpData->recvBuffer = NULL;
  409         connection->udpData->sendBuffer = NULL;
  410         connection->udpData->isUsingSeqNum = isUsingSeqNum;
  411         connection->udpData->maxPacketSize = maxPacketSize;
  412         /* send sequence numbers always start from 0 */
  413         connection->udpData->sendSeqNum = 0;
  414         /* initially, seed the expectedRecvSeqNum from the first 
  415          * received packet */
  416         connection->udpData->resetExpectedRecvSeqNum = 1;      
  417         connection->udpData->recvBuffer = createUDPPacketBuffer(maxPacketSize);
  418         if (connection->udpData->recvBuffer == NULL) {
  419            printf("initConnectionData:createUDPPacketBuffer failed.\n");
  420            freeConnectionData(connection);
  421            retVal = RTIOSTREAM_ERROR;
  422            return retVal; 
  423         }
  424         if (maxPacketSize > UDP_MAX_PACKET_SIZE) {
  425            /* packet size cannot exceed the maximum 
  426             * UDP packet size */
  427            printf("initConnectionData: udpmaxpacketsize must be less than %d\n", UDP_MAX_PACKET_SIZE);
  428            freeConnectionData(connection);
  429            retVal = RTIOSTREAM_ERROR;
  430            return retVal; 
  431         }
  432         if (connection->udpData->isUsingSeqNum) {
  433            /* packet size must be larger than the size
  434             * of the sequence number */
  435            if (maxPacketSize <= UDP_SEQ_NUM_SIZE) {
  436               printf("initConnectionData: udpmaxpacketsize must be larger than %d\n", UDP_SEQ_NUM_SIZE);
  437               freeConnectionData(connection);
  438               retVal = RTIOSTREAM_ERROR;
  439               return retVal; 
  440            }
  441            /* send buffer will be required in order to add the sequence
  442             * number to the outgoing data */
  443            connection->udpData->sendBuffer = createUDPPacketBuffer(maxPacketSize);
  444            if (connection->udpData->sendBuffer == NULL) {
  445               printf("initConnectionData:createUDPPacketBuffer failed.\n");
  446               freeConnectionData(connection);
  447               retVal = RTIOSTREAM_ERROR;
  448               return retVal; 
  449            }
  450         }
  451      }
  452   
  453      if (isServer) {
  454         /* initialize server data */
  455         connection->serverData = malloc(sizeof(ServerData));
  456         if (connection->serverData == NULL) {
  457            printf("initConnectionData:ServerData malloc failed.\n");
  458            freeConnectionData(connection);
  459            retVal = RTIOSTREAM_ERROR;
  460            return retVal; 
  461         }
  462         connection->serverData->port = serverPort;
  463         connection->serverData->serverInfoFile = serverInfoFile;
  464         /* provided sock is the listening sock */
  465         connection->serverData->listenSock = sock;
  466         /* later call to serverAcceptSocket will set sock */ 
  467         connection->sock = INVALID_SOCKET;
  468      }
  469      else {
  470         /* store the provided socket */
  471         connection->sock = sock;
  472      }
  473   
  474      if (isVerbose) {
  475         if (connection->protocol == TCP_PROTOCOL) {
  476            printf("Connection id %d, protocol: TCP/IP\n", connectionID);
  477         }
  478         else {
  479            printf("Connection id %d, protocol: UDP/IP\n", connectionID);
  480            printf("Connection id %d, maxPacketSize: %d\n", connectionID, 
  481                                                            connection->udpData->maxPacketSize);
  482            printf("Connection id %d, isUsingSeqNum: %d\n", connectionID, 
  483                                                            connection->udpData->isUsingSeqNum);
  484         }
  485         {
  486            /* display the size of the socket receive buffer */
  487            rtiostream_socklen_t optionLen = sizeof(int);
  488            int optionValue;
  489            getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *) &optionValue, &optionLen);
  490            printf("Connection id %d, socket receive buffer size: %d\n", connectionID, optionValue);
  491         }
  492         printf("Connection id %d, blockingRecvTimeout: %d\n", connectionID, 
  493                                                               connection->blockingRecvTimeout);
  494         if (connection->isServer) {
  495            printf("Connection id %d, type: server\n", connectionID);         
  496            if (connection->serverData->serverInfoFile != NULL) {
  497               printf("Connection id %d, server info file: %s\n", connectionID, 
  498                                                                  connection->serverData->serverInfoFile);
  499            }
  500         }
  501         else {
  502            printf("Connection id %d, type: client\n", connectionID);
  503         }
  504         printf("Connection id %d, socket id %d\n", connectionID, (int) sock);
  505         /* relevant to both clients and servers */
  506         printf("Connection id %d, server port: %d\n", connectionID, serverPort);
  507      }
  508      return retVal;
  509   }
  510   
  511   /* Function: getConnectionData =================================================
  512    * Abstract:
  513    *  Retrieves a ConnectionData instance given its connectionID 
  514    *  (as returned by initConnectionData) 
  515    *
  516    * NOTE: An invalid connectionID will lead to a NULL pointer being returned 
  517    */
  518   static ConnectionData * getConnectionData(int connectionID) {
  519      /* return NULL for invalid or uninitialized connectionIDs */
  520      ConnectionData * connection = NULL;
  521      if ((connectionID >= 0) && (connectionID < MAX_NUM_CONNECTIONS)) {
  522         if (connectionDataArray[connectionID].isInUse) {
  523            connection = &connectionDataArray[connectionID];
  524         }
  525      }
  526      return connection;
  527   }
  528   
  529   /* Function: getConnectionID =================================================
  530    * Abstract:
  531    *  Returns a connectionID corresponding to a ConnectionData that is not 
  532    *  already in use.
  533    *
  534    *  Returns RTIOSTREAM_ERROR if all available ConnectionData instances are 
  535    *  already in use.
  536    */
  537   static int getConnectionID(void) {
  538      int connectionID;
  539      int foundUnusedConnectionData = 0;
  540      /* linear search for an unused ConnectionData */
  541      for (connectionID = 0; connectionID < MAX_NUM_CONNECTIONS; connectionID++) {      
  542         if (!connectionDataArray[connectionID].isInUse) {
  543            foundUnusedConnectionData = 1;
  544            break;
  545         }
  546      }
  547      if (!foundUnusedConnectionData) {
  548         /* all ConnectionData's are in use */
  549         printf("getConnectionID: All %d available connections are in use.\n", MAX_NUM_CONNECTIONS);
  550         connectionID = RTIOSTREAM_ERROR;
  551      }
  552      return connectionID;
  553   }
  554   
  555   /* Function: freeConnectionData =================================================
  556    * Abstract:
  557    *  Frees memory associated with the ConnectionData referenced by connectionID.
  558    *  Marks the ConnectionData instance as no longer in use.
  559    */
  560   static void freeConnectionData(ConnectionData * connection) {
  561      /* mark the ConnectionData as not in use */
  562      connection->isInUse = 0;
  563      /* free dynamic memory */
  564      if (connection->protocol == UDP_PROTOCOL) {
  565         freeUDPPacketBuffer(&connection->udpData->recvBuffer);
  566         if (connection->udpData->isUsingSeqNum) {
  567            freeUDPPacketBuffer(&connection->udpData->sendBuffer);
  568         }
  569         free(connection->udpData);
  570         connection->udpData = NULL;
  571      }
  572      if (connection->isServer) {
  573         free(connection->serverData);
  574         connection->serverData = NULL;
  575      }
  576   }
  577   
  578   /* Function: createUDPPacketBuffer =================================================
  579    * Abstract:
  580    *  Allocates storage for and initializes a UDPPacketBuffer
  581    */
  582   static UDPPacketBuffer * createUDPPacketBuffer(int maxPacketSize) {
  583      /* initialize the UDP packet buffer */
  584      UDPPacketBuffer * udpPacketBuffer = malloc(sizeof(UDPPacketBuffer));      
  585      if (udpPacketBuffer == NULL) {
  586         printf("createUDPPacketBuffer:UDPPacketBuffer malloc failed.\n");
  587         return udpPacketBuffer; 
  588      }
  589      /* allocate the buffer */
  590      udpPacketBuffer->buffer = calloc(maxPacketSize, sizeof(char));
  591      if (udpPacketBuffer->buffer == NULL) {
  592         printf("createUDPPacketBuffer:UDPPacketBuffer buffer malloc failed.\n");
  593         /* free everything we allocated */
  594         free(udpPacketBuffer);
  595         udpPacketBuffer = NULL;
  596         return udpPacketBuffer; 
  597      }
  598      resetUDPPacketBuffer(udpPacketBuffer);
  599      return udpPacketBuffer;
  600   }
  601   
  602   /* Function: freeUDPPacketBuffer =================================================
  603    * Abstract:
  604    *  Frees memory associated with the referenced UDPPacketBuffer 
  605    */
  606   static void freeUDPPacketBuffer(UDPPacketBuffer ** udpPacketBuffer) {
  607      if (*udpPacketBuffer != NULL) {
  608         /* free the buffer */
  609         free((*udpPacketBuffer)->buffer);
  610         (*udpPacketBuffer)->buffer = NULL;
  611         /* free the container */
  612         free(*udpPacketBuffer);
  613         *udpPacketBuffer = NULL;
  614      }
  615   }
  616   
  617   /* Function: resetUDPPacketBuffer =================================================
  618    * Abstract:
  619    *  Resets the referenced UDP Packet Buffer so that it is ready to receive fresh data
  620    */
  621   static void resetUDPPacketBuffer(UDPPacketBuffer * udpPacketBuffer) {
  622      udpPacketBuffer->dataPtr = udpPacketBuffer->buffer;
  623      udpPacketBuffer->dataAvail = 0;
  624   }
  625   
  626   /* Function: socketDataPending =================================================
  627    * Abstract:
  628    *  Returns true, via the 'pending' arg, if data is pending on the comm line.
  629    *  Returns false otherwise.
  630    *
  631    *  RTIOSTREAM_NO_ERROR is returned on success, RTIOSTREAM_ERROR on failure.
  632    */
  633   static int socketDataPending(
  634       const SOCKET sock,
  635       ConnectionData * connection,
  636       int    *outPending, 
  637       int timeoutSecs)
  638   {
  639       fd_set          ReadFds;
  640       int             pending;
  641       struct timeval  tval;
  642       struct timeval * tvalPtr;
  643       int retVal = RTIOSTREAM_NO_ERROR;
  644   
  645       if (connection->protocol == UDP_PROTOCOL) {
  646          /* first check the UDP buffer */
  647          UDPPacketBuffer * udpPacketBuffer = connection->udpData->recvBuffer;
  648          if (udpPacketBuffer->dataAvail) {
  649             *outPending = 1;
  650             return retVal;
  651          }
  652       } 
  653   
  654       FD_ZERO(&ReadFds);
  655       FD_SET(sock, &ReadFds);
  656   
  657       switch (timeoutSecs) {
  658          case BLOCKING_RECV_TIMEOUT_NEVER:
  659             /* specify null pointer for blocking */
  660             tvalPtr = NULL;
  661             break;
  662          case BLOCKING_RECV_TIMEOUT_10MS:
  663             /* set up the 10ms time-val */
  664             tval.tv_sec  = 0;
  665             tval.tv_usec = 10000;
  666             tvalPtr = &tval;
  667             break;
  668          default:
  669             /* set up the time-val */
  670             tval.tv_sec  = timeoutSecs;
  671             tval.tv_usec = 0;
  672             tvalPtr = &tval;
  673             break;
  674       }
  675   
  676       /*
  677        * Casting the first arg to int removes warnings on windows 64-bit
  678        * platform.  It is safe to cast a SOCKET to an int here because on
  679        * Linux SOCKET is typedef'd to int and on windows the first argument
  680        * to select is ignored (so it doesn't matter what the value is).
  681        */
  682       pending = select((int)(sock + 1), &ReadFds, NULL, NULL, tvalPtr);
  683       if (pending == SOCK_ERR) {
  684           retVal = RTIOSTREAM_ERROR;
  685       }
  686   
  687       *outPending = (pending==1);
  688       return(retVal);    
  689   
  690   } /* end socketDataPending */ 
  691   
  692   /* Function: initialUDPServerRecvfrom =====================================================
  693    * Abstract:
  694    *  Reads data from the client via "recvfrom" into the UDP packet buffer.
  695    *  The client sockaddr is returned via clientSA and clientSALen.
  696    *
  697    *  RTIOSTREAM_NO_ERROR is returned on success, RTIOSTREAM_ERROR is returned on
  698    *  failure.
  699    */
  700   static int initialUDPServerRecvfrom(ConnectionData * connection,
  701                                       struct sockaddr * clientSA,
  702                                       rtiostream_socklen_t * clientSALen) {
  703      int nRead;
  704      int retVal;
  705      UDPPacketBuffer * udpPacketBuffer = connection->udpData->recvBuffer;
  706      /* reset */ 
  707      resetUDPPacketBuffer(udpPacketBuffer);
  708      /* initialize ahead of call to recvfrom */
  709      *clientSALen = sizeof(*clientSA);
  710      /* read into UDP buffer from the listenSock
  711       * and get sockaddr of the client */
  712      nRead = recvfrom(connection->serverData->listenSock, 
  713            udpPacketBuffer->dataPtr, 
  714            connection->udpData->maxPacketSize, 
  715            0U, 
  716            clientSA, 
  717            clientSALen);
  718   
  719      if (nRead == SOCK_ERR) {
  720         retVal = RTIOSTREAM_ERROR;
  721      } else {
  722         /* set dataAvail */
  723         udpPacketBuffer->dataAvail = nRead;
  724         /* handle optional sequence number */
  725         retVal = processUDPRecvSeqNum(connection);
  726      }
  727      return retVal;
  728   }
  729   
  730   /* Function: processUDPRecvSeqNum =====================================================
  731    * Abstract:
  732    *  Processes sequence numbers in received UDP datagrams.
  733    *
  734    *  RTIOSTREAM_NO_ERROR is returned on success, RTIOSTREAM_ERROR is returned on
  735    *  failure.
  736    */
  737   static int processUDPRecvSeqNum(ConnectionData * connection) {
  738      int retVal = RTIOSTREAM_NO_ERROR;
  739      if (connection->udpData->isUsingSeqNum) {
  740         UDPPacketBuffer * udpPacketBuffer = connection->udpData->recvBuffer;
  741         /* process sequence number */
  742         udpSeqNum_T recvSeqNum;
  743         if (udpPacketBuffer->dataAvail < UDP_SEQ_NUM_SIZE) {
  744            printf("No receive sequence number found.\n");
  745            retVal = RTIOSTREAM_ERROR;
  746            return retVal; 
  747         }
  748         /* read sequence number from the buffer 
  749          *
  750          * sequence number is always transmitted / received in 
  751          * host Endian */
  752         memcpy(&recvSeqNum,
  753               udpPacketBuffer->dataPtr,
  754               UDP_SEQ_NUM_SIZE);
  755         udpPacketBuffer->dataPtr += UDP_SEQ_NUM_SIZE;
  756         udpPacketBuffer->dataAvail -= UDP_SEQ_NUM_SIZE;
  757         if (connection->isVerbose) {
  758           printf("Received UDP packet with sequence number: %u\n", recvSeqNum);
  759         }
  760         if (connection->udpData->resetExpectedRecvSeqNum) {
  761            /* reset the expected sequence number */
  762            connection->udpData->expectedRecvSeqNum = recvSeqNum + 1;
  763            connection->udpData->resetExpectedRecvSeqNum = 0;
  764         }
  765         else {
  766            /* compare with expected receive seq num */
  767            if (recvSeqNum != connection->udpData->expectedRecvSeqNum) {
  768               printf("UDP packet sequence number mismatch. Expected #: %d, Actual #: %d\n", 
  769                     connection->udpData->expectedRecvSeqNum, recvSeqNum);
  770               retVal = RTIOSTREAM_ERROR;
  771            } 
  772            else {
  773               /* increment expected receive seq num */
  774               connection->udpData->expectedRecvSeqNum++;
  775            }
  776         }
  777      }
  778      return retVal;
  779   }
  780   
  781   /* Function: socketDataGet =====================================================
  782    * Abstract:
  783    *  Attempts to gets the specified number of bytes from the specified socket.
  784    *  The number of bytes read is returned via the 'sizeRecvd' parameter.
  785    *  RTIOSTREAM_NO_ERROR is returned on success, RTIOSTREAM_ERROR is returned on
  786    *  failure.
  787    *
  788    * NOTES:
  789    *  o it is not an error for 'sizeRecvd' to be returned as 0
  790    *  o this function blocks if no data is available
  791    */
  792   static int socketDataGet(ConnectionData * connection,
  793       char          *dst,
  794       const size_t   size,
  795       size_t        *sizeRecvd)
  796   {
  797       int nRead = 0;
  798       int retVal = RTIOSTREAM_NO_ERROR; 
  799       /* Ensure size is not out of range for socket API recv function */
  800       int sizeLim = (int) MIN(size, INT_MAX);
  801   
  802       if (connection->protocol == TCP_PROTOCOL) {
  803          nRead = recv(connection->sock, dst, sizeLim, 0U);
  804          if (nRead == SOCK_ERR) {
  805             retVal = RTIOSTREAM_ERROR;
  806          } else {
  807             retVal = RTIOSTREAM_NO_ERROR;
  808          }
  809       }
  810       else { 
  811          UDPPacketBuffer * udpPacketBuffer = connection->udpData->recvBuffer;
  812          /* receive more data in to the buffer if required */
  813          if (udpPacketBuffer->dataAvail == 0) {         
  814             /* reset */ 
  815             resetUDPPacketBuffer(udpPacketBuffer);
  816             /* read into buffer */
  817             nRead = recv(connection->sock, 
  818                          udpPacketBuffer->dataPtr, 
  819                          connection->udpData->maxPacketSize, 
  820                          0U);
  821             
  822             if (nRead == SOCK_ERR) {
  823                retVal = RTIOSTREAM_ERROR;
  824             } else {
  825                udpPacketBuffer->dataAvail = nRead;
  826                /* handle optional sequence number */
  827                retVal = processUDPRecvSeqNum(connection);             
  828                if (retVal == RTIOSTREAM_ERROR) {
  829                   return retVal;
  830                }
  831             }
  832          }
  833          /* get data from the buffer */
  834          /* for the special case where we request a  */
  835          /* size of 0 bytes, return the whole buffer */
  836          if (udpPacketBuffer->dataAvail) {
  837             if (size == 0) {
  838               nRead = udpPacketBuffer->dataAvail;
  839             } else {
  840               nRead = MIN(udpPacketBuffer->dataAvail, sizeLim);
  841             }
  842             memcpy(dst, (void *) udpPacketBuffer->dataPtr, nRead);
  843             udpPacketBuffer->dataAvail -= nRead;
  844             udpPacketBuffer->dataPtr += nRead;
  845          }
  846       }
  847   
  848       if (retVal!=RTIOSTREAM_ERROR) {
  849           *sizeRecvd = (size_t) nRead;
  850       }
  851   
  852       return retVal;
  853   } /* end socketDataGet */ 
  854   
  855   
  856   /* Function: socketDataSet =====================================================
  857    * Abstract:
  858    *  Utility function to send data via the specified socket
  859    */
  860   static int socketDataSet(
  861       ConnectionData * connection,
  862       const void *src,
  863       const size_t size,
  864       size_t *sizeSent)
  865   {
  866       int nSent;    
  867       int retVal = RTIOSTREAM_NO_ERROR;
  868       const void *sendSrc = src;    
  869   
  870       /* Ensure size is not out of range for socket API send function */
  871       int sizeLim = (int) MIN(size, INT_MAX);
  872   
  873       if (connection->protocol == UDP_PROTOCOL) {
  874          /* limit sends according to max packet size */
  875          int maxPacketSize = connection->udpData->maxPacketSize;
  876          if (connection->udpData->isUsingSeqNum) {          
  877             int transferAmount;
  878             UDPPacketBuffer * udpPacketBuffer = connection->udpData->sendBuffer;
  879             /* need to apply sequence number and then increment it */
  880             resetUDPPacketBuffer(udpPacketBuffer); 
  881             /* set data src */          
  882             sendSrc = udpPacketBuffer->dataPtr;
  883             /* add sequence number to the buffer 
  884              *
  885              * sequence number is always transmitted / received in 
  886              * host Endian */
  887             memcpy(udpPacketBuffer->dataPtr, 
  888                    &connection->udpData->sendSeqNum,
  889                    UDP_SEQ_NUM_SIZE);
  890             udpPacketBuffer->dataPtr += UDP_SEQ_NUM_SIZE;
  891             udpPacketBuffer->dataAvail += UDP_SEQ_NUM_SIZE;                
  892             /* copy the data - don't overflow the packet buffer */
  893             transferAmount = MIN(sizeLim, maxPacketSize - udpPacketBuffer->dataAvail);
  894             memcpy(udpPacketBuffer->dataPtr,
  895                    src, 
  896                    transferAmount);
  897             udpPacketBuffer->dataAvail += transferAmount;                                   
  898             sizeLim = udpPacketBuffer->dataAvail;
  899          }
  900          else {
  901             sizeLim = MIN(maxPacketSize, sizeLim);
  902          }
  903       }
  904   
  905   #ifndef VXWORKS
  906       nSent = send(connection->sock, sendSrc, sizeLim, 0);
  907   #else
  908       /*
  909        * VXWORKS send prototype does not have src as const.  This suppresses
  910        * the compiler warning.
  911        */
  912       nSent = send(connection->sock, (char *)sendSrc, sizeLim, 0);
  913   #endif
  914       if (nSent == SOCK_ERR) {
  915           retVal = RTIOSTREAM_ERROR;
  916       } else { 
  917           if ((connection->protocol == UDP_PROTOCOL) &&
  918               (connection->udpData->isUsingSeqNum) && 
  919               (nSent > 0)) {
  920              if (nSent < (int) UDP_SEQ_NUM_SIZE) {
  921                 /* expected the sequence number to have transmitted */
  922                 retVal = RTIOSTREAM_ERROR;
  923                 return retVal;
  924              }
  925              else {
  926                 if (connection->isVerbose) {
  927                    printf("Sent UDP packet with sequence number: %u\n", connection->udpData->sendSeqNum);
  928                 }
  929                 /* increment sequence number */
  930                 connection->udpData->sendSeqNum++;
  931                 nSent -= UDP_SEQ_NUM_SIZE;
  932              }          
  933           }
  934           *sizeSent = (size_t)nSent;
  935       }
  936   
  937       return retVal;
  938   }
  939   
  940   /* Function: serverStreamRecv =================================================
  941    * Abstract:
  942    *  Send data from the server-side
  943    */
  944   static int serverStreamRecv( 
  945       ConnectionData * connection, 
  946       void * dst,
  947       size_t size,
  948       size_t * sizeRecvd)
  949   {
  950       int retVal = RTIOSTREAM_NO_ERROR;
  951       *sizeRecvd = 0;
  952   
  953       if (connection->sock == INVALID_SOCKET) {
  954          /* Attempt to open connection */
  955          serverAcceptSocket(connection);
  956       }
  957   
  958       if (connection->sock != INVALID_SOCKET) {
  959           int pending;
  960           if (connection->blockingRecvTimeout != BLOCKING_RECV_TIMEOUT_NEVER) {
  961              /* only call costly "select" if necessary */
  962              retVal = socketDataPending(connection->sock, 
  963                                         connection,
  964                                         &pending, 
  965                                         connection->blockingRecvTimeout);
  966           }
  967           else {
  968              /* block in "recv" if necessary */
  969              pending = 1;
  970           }
  971   
  972           if ( (pending !=0) && (retVal==RTIOSTREAM_NO_ERROR) && (size>0) ) {
  973              
  974               retVal = socketDataGet(connection, (char *)dst, size, sizeRecvd);
  975               
  976               if (*sizeRecvd == 0) {
  977                   
  978                   if (errno == RTIOSTREAM_ECONNRESET) {
  979                       /* If we are closing the connection and we received this
  980                        * error, it means the other side of the connection was
  981                        * already closed.  Since we are expecting this, we can
  982                        * ignore this particular error.
  983                        */
  984                       retVal = RTIOSTREAM_NO_ERROR;
  985                   } else {
  986                       /* Connection closed gracefully by client */
  987                   }
  988   
  989                   close(connection->sock);
  990                   connection->sock = INVALID_SOCKET;
  991               }
  992           }
  993           
  994           if ( retVal == RTIOSTREAM_ERROR ) {
  995               close(connection->sock);
  996               connection->sock = INVALID_SOCKET;
  997           }
  998       }
  999   
 1000       return retVal;
 1001   }
 1002   
 1003   /* Function: serverOpenSocket =================================================
 1004    * Abstract:
 1005    *  Opens the listening socket to be used for accepting an incoming connection.
 1006    */
 1007   static SOCKET serverOpenSocket(int port, char * serverInfoFile, CommsProtocol protocol)
 1008   {
 1009   
 1010       struct sockaddr_in serverAddr;
 1011       int sockStatus;
 1012       rtiostream_socklen_t sFdAddSize     = (rtiostream_socklen_t) sizeof(struct sockaddr_in);
 1013       SOCKET lFd;
 1014       int option;     
 1015   
 1016       /*
 1017        * Create a TCP or UDP based socket.
 1018        */
 1019       memset((void *) &serverAddr,0,(size_t)sFdAddSize);
 1020       serverAddr.sin_family      = AF_INET;
 1021       serverAddr.sin_port        = htons((unsigned short int) port);
 1022       serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 1023   
 1024       if (protocol == TCP_PROTOCOL) {
 1025          lFd = socket(AF_INET, SOCK_STREAM, 0);
 1026       }
 1027       else {
 1028          lFd = socket(AF_INET, SOCK_DGRAM, 0);
 1029       }
 1030   
 1031       if (lFd == INVALID_SOCKET) {
 1032          printf("socket() call failed.\n");
 1033       } else {
 1034          /*
 1035           * Listening socket should always use the SO_REUSEADDR option
 1036           * ("Unix Network Programming - Networking APIs:Sockets and XTI",
 1037           *   Volume 1, 2nd edition, by W. Richard Stevens).
 1038           */
 1039          option = 1;
 1040          sockStatus = 
 1041             setsockopt(lFd,SOL_SOCKET,SO_REUSEADDR,(char*)&option,sizeof(option));
 1042          if (sockStatus == SOCK_ERR) {
 1043             printf("setsocketopt() call failed.\n");
 1044             close(lFd);
 1045             lFd = INVALID_SOCKET;
 1046          }
 1047          if (protocol == TCP_PROTOCOL) {          
 1048             /* Disable Nagle's Algorithm*/ 
 1049             option = 1;
 1050             sockStatus = 
 1051                setsockopt(lFd,IPPROTO_TCP,TCP_NODELAY,(char*)&option,sizeof(option));
 1052             if (sockStatus == SOCK_ERR) { 
 1053                printf("setsocketopt() TCP_NODELAY call failed.\n");
 1054                close(lFd); 
 1055                lFd = INVALID_SOCKET; 
 1056             }
 1057          } 
 1058          else {
 1059             /* increase the UDP socket receive size to decrease the 
 1060              * possibility of buffer overflow */
 1061             option = UDP_SOCKET_RECEIVE_SIZE_REQUEST;
 1062             sockStatus = 
 1063                setsockopt(lFd, SOL_SOCKET, SO_RCVBUF,(char*)&option, sizeof(option));
 1064             if (sockStatus == SOCK_ERR) { 
 1065                printf("setsocketopt() SO_RCVBUF call failed.\n");
 1066                close(lFd); 
 1067                lFd = INVALID_SOCKET; 
 1068             }         
 1069          }
 1070       }
 1071   
 1072       if (lFd != INVALID_SOCKET) {
 1073          sockStatus = bind(lFd, (struct sockaddr *) &serverAddr, sFdAddSize);
 1074          if (sockStatus == SOCK_ERR) {
 1075             printf("bind() call failed: %s\n", strerror(errno));
 1076             close(lFd);
 1077             lFd = INVALID_SOCKET;
 1078          }
 1079       }
 1080   
 1081       if (lFd != INVALID_SOCKET) {
 1082          if (port == 0) {
 1083             /* port 0 specifies dynamic free port allocation
 1084              * reuse serverAddr to store the actual address / port */
 1085             sockStatus = getsockname(lFd, (struct sockaddr *) &serverAddr, &sFdAddSize);           
 1086             if (sockStatus == SOCK_ERR) {
 1087                fprintf(stderr,"getsockname() call failed: %s\n", strerror(errno));
 1088                close(lFd);
 1089                lFd = INVALID_SOCKET;               
 1090             } else { 
 1091                if(serverInfoFile != NULL) {
 1092                   FILE* fh;
 1093   
 1094                   /* Open file in append mode to save info already stored in the file*/
 1095                   fh = fopen(serverInfoFile,"a"); 
 1096                   #ifdef __LCC64__
 1097                   /* This is needed due to an issue with LCC64, see the following geck:  g919889 */
 1098                   fseek ( fh, 0 , SEEK_END );
 1099                   #endif
 1100                   if (fh == NULL) {
 1101                      fprintf(stderr,"Unable to open output file to write server port number: %s\n", strerror(errno));
 1102                      lFd = INVALID_SOCKET;
 1103                   }
 1104   
 1105                   (void)fprintf(fh, "Server Port Number: %u\n", ntohs(serverAddr.sin_port));
 1106                   fclose(fh);
 1107                } else {
 1108                   /* write the server port number to stdout */
 1109                   SERVER_PORT_PRINTF("Server Port Number: %u\n", ntohs(serverAddr.sin_port));
 1110                }
 1111             }                 
 1112          }
 1113       }
 1114       if (protocol == TCP_PROTOCOL) {
 1115          if (lFd != INVALID_SOCKET) {
 1116             sockStatus = listen(lFd, 2);
 1117             if (sockStatus == SOCK_ERR) {
 1118                printf("listen() call failed.\n");
 1119                close(lFd);
 1120                lFd = INVALID_SOCKET;
 1121             }
 1122          }
 1123       }
 1124       return lFd;
 1125   }
 1126   /* Function: serverAcceptSocket =================================================
 1127    * Abstract:
 1128    *  Called when the target is not currently connected to the host, this 
 1129    *  function attempts to open the connection.  
 1130    *
 1131    *  In the case of sockets, this is a passive operation in that the host
 1132    *  initiates contact, the target simply listens for connection requests.
 1133    *
 1134    * NOTES:
 1135    
 1136    * Blocks according to blockingRecvTimeout. When
 1137    * polling, there may be no open requests pending.  In this case, this
 1138    * function returns without making a connection; this is not an error.
 1139    */
 1140   static void serverAcceptSocket(ConnectionData * connection)
 1141   {
 1142      struct sockaddr_in clientAddr;
 1143      rtiostream_socklen_t     sFdAddSize     = sizeof(struct sockaddr_in);
 1144      SOCKET  cFd            = INVALID_SOCKET;
 1145      int error             = RTIOSTREAM_NO_ERROR;
 1146      int pending;    
 1147   
 1148      /* Check that the listening socket is still valid and open a new socket if
 1149       * not */
 1150      if (connection->serverData->listenSock == INVALID_SOCKET) {
 1151         connection->serverData->listenSock = serverOpenSocket(connection->serverData->port,
 1152               connection->serverData->serverInfoFile, 
 1153               connection->protocol);
 1154      }
 1155   
 1156      /* pass listenSock rather than sock */
 1157      error = socketDataPending(connection->serverData->listenSock, 
 1158            connection,
 1159            &pending, 
 1160            connection->blockingRecvTimeout);
 1161   
 1162      if ( (pending > 0) && (error==RTIOSTREAM_NO_ERROR) ) {
 1163         if (connection->protocol == TCP_PROTOCOL) {
 1164            /*
 1165             * Wait to accept a connection on the comm socket.
 1166             */
 1167            cFd = accept(connection->serverData->listenSock, 
 1168                        (struct sockaddr *)&clientAddr,
 1169                        &sFdAddSize);
 1170   
 1171            if (cFd == INVALID_SOCKET) {
 1172               printf("accept() for comm socket failed.\n");
 1173               error = RTIOSTREAM_ERROR;
 1174            } 
 1175   
 1176            if (error == RTIOSTREAM_ERROR) {
 1177               close(connection->serverData->listenSock);
 1178               connection->serverData->listenSock = INVALID_SOCKET;
 1179            } 
 1180         }
 1181         else {
 1182            /* UDP - data is pending */
 1183            struct sockaddr clientSA;
 1184            rtiostream_socklen_t clientSALen;
 1185            /* new connection, make sure we reset expectedRecvSeqNum, 
 1186             * if sequence numbers are in use */
 1187            connection->udpData->resetExpectedRecvSeqNum = 1;
 1188            /* Do the initial UDP server "recvfrom" to get the 
 1189             * client sockaddr.   Data read will be placed 
 1190             * ready in the UDP packet buffer. */
 1191            error = initialUDPServerRecvfrom(connection, &clientSA, &clientSALen); 
 1192            if (error == RTIOSTREAM_ERROR) {
 1193               close(connection->serverData->listenSock);
 1194               connection->serverData->listenSock = INVALID_SOCKET;
 1195               printf("initialUDPServerRecvfrom() failed.\n");
 1196            }
 1197            else {
 1198               /* connect exclusively to the client so we no longer
 1199                * have to use recvfrom / sendto */
 1200               if (connect(connection->serverData->listenSock, 
 1201                           &clientSA, 
 1202                           clientSALen) == SOCK_ERR) {
 1203                  close(connection->serverData->listenSock);
 1204                  connection->serverData->listenSock = INVALID_SOCKET;
 1205                  printf("Server connect() failed.\n");
 1206               } 
 1207            } 
 1208            /* for UDP, the socket and listening socket are the same */
 1209            cFd = connection->serverData->listenSock;
 1210         }
 1211      }
 1212      /* set sock */
 1213      connection->sock = cFd;
 1214   } 
 1215   
 1216   
 1217   /* Function: nameLookup =======================
 1218    * Lookup target network name.
 1219    */
 1220   #if (!defined(VXWORKS))
 1221   static unsigned long nameLookup(char * hostName) {
 1222   
 1223       struct hostent * hp = NULL;
 1224       struct in_addr * iaddr = NULL;
 1225       unsigned long addr = INADDR_NONE;
 1226   
 1227       /*
 1228        * Default to localhost if hostname not specified.
 1229        */
 1230       if (hostName == NULL) {
 1231           static char localhost[] = "localhost";
 1232           hostName = localhost;
 1233       }
 1234       
 1235       /*
 1236        * See if the address is an IPV4 dot separated address:
 1237        */
 1238       addr = inet_addr(hostName);
 1239   
 1240       if (addr == INADDR_NONE) {
 1241           /* Since the address is not an IPV4 dot separated address, 
 1242            * do a name lookup to get this: 
 1243            */
 1244           hp = gethostbyname(hostName);
 1245           if (hp == NULL) {
 1246             printf("gethostbyname() call failed.\n");
 1247     	  addr = INADDR_NONE;
 1248           } else {
 1249             iaddr = (struct in_addr *) hp->h_addr;
 1250             addr = iaddr->s_addr;
 1251           }
 1252       }
 1253       return(addr);
 1254   }
 1255   #endif
 1256   
 1257   /* Function: processArgs ====================================================
 1258    * Abstract:
 1259    *  Process the arguments specified by the user when opening the rtIOStream.
 1260    *      
 1261    *  If any unrecognized options are encountered, ignore them.
 1262    *
 1263    * Returns zero if successful or RTIOSTREAM_ERROR if 
 1264    * an error occurred.
 1265    *
 1266    *  o IMPORTANT!!!
 1267    *    As the arguments are processed, their strings should be NULL'd out in
 1268    *    the argv array. 
 1269    */
 1270   static int processArgs(
 1271       const int       argc,
 1272       void         *  argv[],
 1273       char        **  hostName, 
 1274       unsigned int *  portNum,
 1275       unsigned int *  isClient,
 1276       int          *  isBlocking,
 1277       int          *  recvTimeout, 
 1278       char        **  serverInfoFile, 
 1279       CommsProtocol * protocol, 
 1280       int           * maxPacketSize, 
 1281       int           * isVerbose, 
 1282       int           * isUsingSeqNum)
 1283   {
 1284       int        retVal    = RTIOSTREAM_NO_ERROR;
 1285       int        count           = 0;
 1286   
 1287       while(count < argc) {
 1288           const char *option = (char *)argv[count];
 1289           count++;
 1290   
 1291           if (option != NULL) {
 1292   
 1293               if ((strcmp(option, "-hostname") == 0) && (count != argc)) {
 1294   
 1295                   *hostName = (char *)argv[count];
 1296                   count++;
 1297                   argv[count-2] = NULL;
 1298                   argv[count-1] = NULL;
 1299   
 1300               } else if ((strcmp(option, "-port") == 0) && (count != argc)) {
 1301                   char       tmpstr[2];
 1302                   int itemsConverted;
 1303                   const char *portStr = (char *)argv[count];
 1304   
 1305                   count++;     
 1306                   
 1307                   itemsConverted = sscanf(portStr,"%d%1s", (int *) portNum, tmpstr);
 1308                   if ( (itemsConverted != 1) || 
 1309                        ( ((*portNum != 0) && (*portNum < 255)) || (*portNum > 65535)) 
 1310                       ) {
 1311                       
 1312                       retVal = RTIOSTREAM_ERROR;
 1313                   } else {
 1314   
 1315                       argv[count-2] = NULL;
 1316                       argv[count-1] = NULL;
 1317                   }           
 1318                   
 1319               } else if ((strcmp(option, "-client") == 0) && (count != argc)) {
 1320                   
 1321                   *isClient = ( strcmp( (char *)argv[count], "1") == 0 );
 1322   
 1323                   count++;
 1324                   argv[count-2] = NULL;
 1325                   argv[count-1] = NULL;
 1326   
 1327               } else if ((strcmp(option, "-blocking") == 0) && (count != argc)) {
 1328                   
 1329                   *isBlocking = ( strcmp( (char *)argv[count], "1") == 0 );
 1330   
 1331                   count++;
 1332                   argv[count-2] = NULL;
 1333                   argv[count-1] = NULL;
 1334   
 1335               } else if ((strcmp(option, "-verbose") == 0) && (count != argc)) {
 1336                   
 1337                   *isVerbose = ( strcmp( (char *)argv[count], "1") == 0 );
 1338   
 1339                   count++;
 1340                   argv[count-2] = NULL;
 1341                   argv[count-1] = NULL;
 1342   
 1343               } else if ((strcmp(option, "-recv_timeout_secs") == 0) && (count != argc)) {
 1344                   char       tmpstr[2];
 1345                   int itemsConverted;
 1346                   const char *timeoutSecsStr = (char *)argv[count];
 1347   
 1348                   count++;     
 1349                   
 1350                   itemsConverted = sscanf(timeoutSecsStr,"%d%1s", (int *) recvTimeout, tmpstr);
 1351                   if ( itemsConverted != 1 ) {
 1352                       retVal = RTIOSTREAM_ERROR;
 1353                   } else {
 1354   
 1355                       argv[count-2] = NULL;
 1356                       argv[count-1] = NULL;
 1357                   }           
 1358   
 1359               } else if((strcmp(option, "-server_info_file") == 0) && (count != argc)) {
 1360                   *serverInfoFile= (char *) argv[count];
 1361                   
 1362                   count++;
 1363                   argv[count-2] = NULL;
 1364                   argv[count-1] = NULL;
 1365               } else if ((strcmp(option, "-protocol") == 0) && (count != argc)) {
 1366                 char * protocolStr = (char *) argv[count];
 1367                 count++;
 1368                 argv[count-2] = NULL;
 1369                 argv[count-1] = NULL;
 1370                 /* initialize dependent properties */
 1371                 *isUsingSeqNum = 0;
 1372                 /* process protocolStr */
 1373                 if (strcmp(protocolStr, TCP_PROTOCOL_STRING) == 0) {
 1374                    *protocol = TCP_PROTOCOL;                
 1375                 }
 1376                 else if (strcmp(protocolStr, UDP_PROTOCOL_STRING) == 0) {
 1377                    *protocol = UDP_PROTOCOL;
 1378                 }
 1379                 else if (strcmp(protocolStr, UDP_PACKET_LOSS_DETECTON_PROTOCOL_STRING) == 0) {
 1380                    *protocol = UDP_PROTOCOL;
 1381                    /* enable sequence number protocol */
 1382                    *isUsingSeqNum = 1;
 1383                 }
 1384                 else {
 1385                    /* unrecognized protocol */
 1386                    retVal = RTIOSTREAM_ERROR;
 1387                 }            
 1388               } else if ((strcmp(option, "-udpmaxpacketsize") == 0) && (count != argc)) {
 1389                  char       tmpstr[2];
 1390                  int itemsConverted;
 1391                  const char *maxUPDSizeStr = (char *)argv[count];
 1392   
 1393                  count++;     
 1394   
 1395                  itemsConverted = sscanf(maxUPDSizeStr,"%d%1s", maxPacketSize, tmpstr);
 1396                  if ( itemsConverted != 1 ) {
 1397                     retVal = RTIOSTREAM_ERROR;
 1398                  } else {
 1399                     argv[count-2] = NULL;
 1400                     argv[count-1] = NULL;
 1401                  }           
 1402               } else{
 1403                   /* do nothing */
 1404               }
 1405           }
 1406       }
 1407       return retVal;
 1408   }
 1409   
 1410   /* Function: clientOpenSocket =================================================
 1411    * Abstract:
 1412    *  Open a connection as Client
 1413    */
 1414   #if (!defined(VXWORKS))
 1415   static SOCKET clientOpenSocket(char * hostName, unsigned int portNum, CommsProtocol protocol) {
 1416       
 1417       struct sockaddr_in sa;
 1418       unsigned long addr = INADDR_NONE;
 1419       int errStatus = RTIOSTREAM_NO_ERROR;
 1420       SOCKET cSock = INVALID_SOCKET;
 1421   
 1422       addr = nameLookup(hostName);
 1423   
 1424       if (addr!=INADDR_NONE) {
 1425           
 1426            sa.sin_addr.s_addr = addr;
 1427            sa.sin_family = AF_INET; /*hp->h_addrtype;*/
 1428            sa.sin_port   = htons((unsigned short) portNum);
 1429   
 1430           /*
 1431            * Create the sockets & make connections.
 1432            */
 1433           if (protocol == TCP_PROTOCOL) {
 1434              cSock = socket(PF_INET,SOCK_STREAM,0);
 1435           } 
 1436           else {
 1437              cSock = socket(PF_INET,SOCK_DGRAM,0);
 1438           }
 1439           if (cSock == INVALID_SOCKET) {
 1440               errStatus = RTIOSTREAM_ERROR;
 1441               printf("socket() call failed for comm socket.\n");
 1442           }
 1443       } else {
 1444         errStatus = RTIOSTREAM_ERROR;
 1445       }
 1446    
 1447       if ((errStatus!=RTIOSTREAM_ERROR) && 
 1448           (protocol == UDP_PROTOCOL)) {
 1449          /* increase the UDP socket receive size to decrease the 
 1450           * possibility of buffer overflow */
 1451          int option = UDP_SOCKET_RECEIVE_SIZE_REQUEST;
 1452          int sockStatus = 
 1453             setsockopt(cSock, SOL_SOCKET, SO_RCVBUF,(char*)&option, sizeof(option));
 1454          if (sockStatus == SOCK_ERR) { 
 1455             printf("setsocketopt() SO_RCVBUF call failed.\n");
 1456             cSock = INVALID_SOCKET;
 1457             errStatus = RTIOSTREAM_ERROR;
 1458          }         
 1459       }
 1460   
 1461       if (errStatus!=RTIOSTREAM_ERROR) {
 1462           if (connect(cSock, (struct sockaddr *)&sa, sizeof(sa)) == SOCK_ERR) {
 1463               char tmp[1024];
 1464   
 1465               sprintf(tmp,
 1466                       "Attempting to establish connection with hostname '%s' "
 1467                       "through port %d.\n", 
 1468                       hostName,
 1469                       ntohs(sa.sin_port));
 1470               cSock = INVALID_SOCKET;
 1471               printf("%s",tmp);
 1472           } 
 1473       }
 1474   
 1475       return cSock;
 1476   }
 1477   #endif
 1478   
 1479   /* Function: waitForClientClose =============================================
 1480    * Abstract:
 1481    *
 1482    * Allow the client to close its end of the socket connection before the server
 1483    * closes its own socket.
 1484    *
 1485    * The server will receive any outstanding data on the socket.   When the server
 1486    * receives 0 bytes, it indicates that it has acknowledged that the client 
 1487    * is closing its socket (this is essential for the client to complete
 1488    * closing its socket without error) or that it timed out waiting for the client to 
 1489    * close its socket.
 1490    *
 1491    */
 1492   static int waitForClientClose(ConnectionData * connection) {
 1493      int retVal = RTIOSTREAM_NO_ERROR;
 1494   #define TMP_BUF_SIZE (40)
 1495      char * tmpBuf[TMP_BUF_SIZE];
 1496      size_t numRecvd;          
 1497      /* cache the original blockingRecvTimeout */
 1498      int savedBlockingRecvTimeout = connection->blockingRecvTimeout;      
 1499      /* wait time for client to close its socket */
 1500      connection->blockingRecvTimeout = BLOCKING_RECV_TIMEOUT_SOCK_SHUTDOWN;
 1501      do {         
 1502         retVal = serverStreamRecv(connection, (void *) tmpBuf, TMP_BUF_SIZE, &numRecvd);
 1503      } while ((numRecvd > 0) && (retVal == RTIOSTREAM_NO_ERROR));
 1504      /* restore blockingRecvTimeout */
 1505      connection->blockingRecvTimeout = savedBlockingRecvTimeout;
 1506   #undef TMP_BUF_SIZE
 1507      return retVal;
 1508   }
 1509   
 1510   /***************** VISIBLE FUNCTIONS ******************************************/
 1511   
 1512   /* Function: rtIOStreamOpen =================================================
 1513    * Abstract:
 1514    *  Open the connection with the target.
 1515    */
 1516   int rtIOStreamOpen(int argc, void * argv[])
 1517   {
 1518       char               *xHostName = NULL; /* default */
 1519       char               *serverInfoFile = NULL; /* default */
 1520       unsigned int        xPortNum     = (SERVER_PORT_NUM); /* default */
 1521       unsigned int        isClient = 0; /* default */
 1522       CommsProtocol       protocol = DEFAULT_PROTOCOL;
 1523       int                 isBlockingRecv = EXT_BLOCKING; /* default */
 1524       int                 blockingRecvTimeout = DEFAULT_BLOCKING_RECV_TIMEOUT; /* rogue value */
 1525       int                 maxPacketSize = DEFAULT_MAX_UDP_PACKET_SIZE;
 1526       int                 isVerbose = DEFAULT_IS_VERBOSE;
 1527       int                 isUsingSeqNum = DEFAULT_IS_USING_SEQ_NUM;
 1528       int result = RTIOSTREAM_NO_ERROR;
 1529       int streamID;
 1530       SOCKET sock = INVALID_SOCKET;
 1531   
 1532       /* determine the streamID for this new connection */
 1533       streamID = getConnectionID();
 1534       if (streamID == RTIOSTREAM_ERROR) {
 1535          result = RTIOSTREAM_ERROR;
 1536          return result;
 1537       }
 1538   
 1539       result = processArgs(argc, argv, 
 1540                            &xHostName, 
 1541                            &xPortNum, 
 1542                            &isClient, 
 1543                            &isBlockingRecv,
 1544                            &blockingRecvTimeout, 
 1545                            &serverInfoFile, 
 1546                            &protocol, 
 1547                            &maxPacketSize, 
 1548                            &isVerbose, 
 1549                            &isUsingSeqNum);    
 1550       if (result == RTIOSTREAM_ERROR) {
 1551          return result;
 1552       }
 1553   
 1554       if (isVerbose) {
 1555          printf("rtIOStreamOpen\n");
 1556       }
 1557   
 1558       if (isBlockingRecv) {
 1559          /* blocking: if blockingRecvTimeout has not been set, initialize to the client or
 1560           * server specific default */
 1561          if ((blockingRecvTimeout == DEFAULT_BLOCKING_RECV_TIMEOUT) ||
 1562              (blockingRecvTimeout < BLOCKING_RECV_TIMEOUT_10MS)) {
 1563             if (isClient) {
 1564                blockingRecvTimeout = DEFAULT_BLOCKING_RECV_TIMEOUT_SECS_CLIENT;
 1565             }
 1566             else {
 1567                blockingRecvTimeout = DEFAULT_BLOCKING_RECV_TIMEOUT_SECS_SERVER;
 1568             }
 1569          }
 1570       }
 1571       else {
 1572          /* not blocking: set the timeout to return immediately */
 1573          blockingRecvTimeout = BLOCKING_RECV_TIMEOUT_NOWAIT;
 1574       }
 1575   
 1576   #ifdef VXWORKS /* UDP is not supported on VxWorks */
 1577       if (protocol == UDP_PROTOCOL) {
 1578          result = RTIOSTREAM_ERROR;
 1579          return result;
 1580       }
 1581   #endif
 1582   
 1583   #ifdef _WIN32
 1584       {
 1585           WSADATA data;
 1586           if (WSAStartup((MAKEWORD(1,1)), &data)) {
 1587               result = RTIOSTREAM_ERROR;
 1588               printf("WSAStartup() call failed.\n");
 1589           }
 1590       }
 1591   #endif
 1592   
 1593       if (result != RTIOSTREAM_ERROR) {
 1594           if (isClient == 1) {
 1595   #if (!defined(VXWORKS)) /* Client side connection not supported on VxWorks */
 1596              sock = clientOpenSocket(xHostName, xPortNum, protocol);
 1597              if (sock == INVALID_SOCKET) {
 1598                 result = RTIOSTREAM_ERROR;
 1599              }
 1600   #endif
 1601           } else {           
 1602              sock = serverOpenSocket(xPortNum, serverInfoFile, protocol);            
 1603              if (sock == INVALID_SOCKET) {
 1604                 result = RTIOSTREAM_ERROR;
 1605              }
 1606           }   
 1607       }
 1608   
 1609       if (result != RTIOSTREAM_ERROR) {
 1610          int isServer;
 1611          if (isClient == 1) {
 1612             isServer = 0;   
 1613          }
 1614          else {
 1615             isServer = 1;
 1616          }
 1617          result = initConnectionData(streamID, 
 1618                isServer, 
 1619                protocol, 
 1620                sock, 
 1621                blockingRecvTimeout,
 1622                maxPacketSize, 
 1623                xPortNum, 
 1624                serverInfoFile, 
 1625                isVerbose, 
 1626                isUsingSeqNum);
 1627       }
 1628       
 1629       if (result != RTIOSTREAM_ERROR) {
 1630          result = streamID;
 1631       }
 1632       else {
 1633          if (sock != INVALID_SOCKET) {
 1634             /* cleanup */
 1635             close(sock);
 1636          }
 1637       }
 1638       return result;
 1639   }
 1640   
 1641   /* Function: rtIOStreamSend =====================================================
 1642    * Abstract:
 1643    *  Sends the specified number of bytes on the comm line. Returns the number of
 1644    *  bytes sent (if successful) or a negative value if an error occurred. As long
 1645    *  as an error does not occur, this function is guaranteed to set the requested
 1646    *  number of bytes; the function blocks if tcpip's send buffer doesn't have
 1647    *  room for all of the data to be sent
 1648    */
 1649   int rtIOStreamSend(
 1650       int streamID,
 1651       const void *src,
 1652       size_t size,
 1653       size_t *sizeSent)
 1654   {
 1655       int retVal = RTIOSTREAM_NO_ERROR;
 1656       ConnectionData * connection = getConnectionData(streamID);
 1657       *sizeSent = 0;
 1658   
 1659       if (connection == NULL) {
 1660          retVal = RTIOSTREAM_ERROR;
 1661          return retVal;
 1662       }
 1663   
 1664       if (connection->isServer) {
 1665           if (connection->sock == INVALID_SOCKET) {
 1666               serverAcceptSocket(connection);
 1667           }
 1668   
 1669           if (connection->sock != INVALID_SOCKET) {
 1670   #ifndef VXWORKS
 1671              retVal = socketDataSet(connection, src, size, sizeSent);
 1672   #else           
 1673              /*
 1674               * VXWORKS send prototype does not have src as const.  This suppresses
 1675               * the compiler warning.
 1676               */
 1677   
 1678              retVal = socketDataSet(connection, (char *)src, size, sizeSent);
 1679   #endif
 1680           }
 1681       } else { /* Client stream */
 1682           retVal = socketDataSet(connection, src, size, sizeSent);
 1683       }
 1684   
 1685       if (connection->isVerbose) {
 1686          printf("rtIOStreamSend (connection id %d): size = %lu, sizeSent = %lu\n", 
 1687                 streamID, 
 1688                 (unsigned long) size, 
 1689                 (unsigned long) *sizeSent);
 1690       }
 1691   
 1692       return retVal;
 1693   }
 1694   
 1695   
 1696   /* Function: rtIOStreamRecv ================================================
 1697    * Abstract: receive data
 1698    *
 1699    */
 1700   int rtIOStreamRecv(
 1701       int      streamID,
 1702       void   * dst, 
 1703       size_t   size,
 1704       size_t * sizeRecvd) 
 1705   {
 1706       int retVal = RTIOSTREAM_NO_ERROR;
 1707       ConnectionData * connection = getConnectionData(streamID);
 1708   
 1709       *sizeRecvd = 0;
 1710   
 1711       if (connection == NULL) {
 1712          retVal = RTIOSTREAM_ERROR;
 1713          return retVal;
 1714       }
 1715   
 1716       if (connection->isServer) {
 1717           retVal = serverStreamRecv(connection, dst, size, sizeRecvd); 
 1718       } else { /* Client stream */
 1719           int pending;
 1720           if (connection->blockingRecvTimeout != BLOCKING_RECV_TIMEOUT_NEVER) {
 1721              /* only call costly "select" if necessary */
 1722              retVal = socketDataPending(connection->sock, 
 1723                                         connection,
 1724                                         &pending, 
 1725                                         connection->blockingRecvTimeout);
 1726           }
 1727           else {
 1728              /* block in "recv" if necessary */
 1729              pending = 1;
 1730           }
 1731           if (pending) {
 1732               retVal = socketDataGet(connection, (char *)dst, size, sizeRecvd);
 1733           }
 1734       }
 1735   
 1736       if (connection->isVerbose) {
 1737          printf("rtIOStreamRecv (connection id %d): size = %lu, sizeRecvd = %lu\n", 
 1738                  streamID, (unsigned long) size, (unsigned long) *sizeRecvd);
 1739       }
 1740       
 1741       return retVal;
 1742   }
 1743   
 1744   /* Function: rtIOStreamClose ================================================
 1745    * Abstract: close the connection.
 1746    *
 1747    */
 1748   int rtIOStreamClose(int streamID)
 1749   {
 1750       int retVal = RTIOSTREAM_NO_ERROR;
 1751       ConnectionData * connection = getConnectionData(streamID);
 1752       if (connection == NULL) {
 1753          retVal = RTIOSTREAM_ERROR;
 1754          return retVal;
 1755       }
 1756   
 1757       if (connection->isVerbose) {
 1758          printf("rtIOStreamClose (connection id %d)\n", streamID);
 1759       }
 1760   
 1761       if (connection->isServer) {
 1762           /* Only if the client actually made a connection */
 1763           if (connection->sock != INVALID_SOCKET) {
 1764               if (connection->protocol == TCP_PROTOCOL) {
 1765                   /* graceful shutdown */
 1766                   retVal = waitForClientClose(connection);
 1767               }
 1768               
 1769               /* close the socket */
 1770               close(connection->sock);
 1771               connection->sock = INVALID_SOCKET;
 1772           }
 1773          if (connection->protocol == TCP_PROTOCOL) {
 1774             /* TCP: additionally close the listening socket
 1775              *
 1776              * for UDP, sock and listenSock are the same
 1777              * socket - avoid closing it twice */
 1778             close(connection->serverData->listenSock);
 1779          }
 1780          /* set to INVALID_SOCKET for all protocol types */
 1781          connection->serverData->listenSock = INVALID_SOCKET;       
 1782       } else {
 1783          SOCKET cSock = connection->sock;
 1784          close(cSock);
 1785   
 1786       }
 1787       freeConnectionData(connection);
 1788       return retVal;
 1789   }
 1790   
 1791